div(
style = "display:flex; gap:2rem; flex-wrap:wrap; margin-bottom:1.5rem;",
div(style = "min-width:260px;", filter_select("cond", "Condition", sd_monthly, ~Condition)),
div(style = "min-width:180px;", filter_slider("cases", "Cases \u2265", sd_monthly, ~cases, min = 0))
)Province Report
Western Cape (WC) — Provincial surveillance report: notification counts, incidence rates, epidemic curves, and condition breakdowns.
Data through: 19 February 2026 | Population: 7,187,004
Total Cases
1,519
%B %Y
Month Δ
↓ 35.1%%
vs previous month
Conditions
26
reporting this month
Top Condition
Tuberculosis:pulmonary
highest case count
Filter
Use these controls to filter the monthly charts and data table below.
Epidemic Curves
Weekly Cases
plot_ly(weekly, x = ~Week, y = ~cases, color = ~Condition,
type = "bar",
hoverinfo = "text",
text = ~paste0(Condition, "<br>Week: ", format(Week, "%d %b %Y"),
"<br>Cases: ", cases)) %>%
layout(barmode = "stack",
xaxis = list(title = "Week starting"),
yaxis = list(title = "Weekly cases"),
legend = list(orientation = "h", y = -0.15))Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Monthly Cases
plot_ly(sd_monthly, x = ~Month, y = ~cases, color = ~Condition,
type = "bar",
hoverinfo = "text",
text = ~paste0(Condition, "<br>", format(Month, "%b %Y"),
"<br>Cases: ", cases)) %>%
layout(barmode = "stack",
xaxis = list(title = "Month"),
yaxis = list(title = "Monthly cases"),
legend = list(orientation = "h", y = -0.15))Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Incidence Trends
plot_ly(weekly, x = ~Week, y = ~incidence_100k, color = ~Condition,
type = "scatter", mode = "lines",
hoverinfo = "text",
text = ~paste0(Condition, "<br>Week: ", format(Week, "%d %b %Y"),
"<br>Inc: ", incidence_100k, " /100k")) %>%
layout(xaxis = list(title = "Week starting"),
yaxis = list(title = "Incidence per 100 000"),
legend = list(orientation = "h", y = -0.15))Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Monthly Incidence
plot_ly(sd_monthly, x = ~Month, y = ~incidence_100k, color = ~Condition,
type = "scatter", mode = "lines+markers",
marker = list(size = 6, opacity = 0.8),
hoverinfo = "text",
text = ~paste0(Condition, "<br>", format(Month, "%b %Y"),
"<br>Inc: ", incidence_100k, " /100k")) %>%
layout(xaxis = list(title = "Month"),
yaxis = list(title = "Incidence per 100 000"),
legend = list(orientation = "h", y = -0.15))Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Warning in RColorBrewer::brewer.pal(max(N, 3L), "Set2"): n too large, allowed maximum for palette Set2 is 8
Returning the palette you asked for with that many colors
Data Tables
Annual Counts
DT::datatable(
annual_wide,
caption = paste0("Annual notification counts — ", prov_name),
extensions = "Buttons",
filter = "top",
rownames = FALSE,
options = list(
dom = "Bfrtip",
buttons = c("csv", "excel", "pdf"),
pageLength = 25,
scrollX = TRUE,
order = list(list(ncol(annual_wide) - 1, "desc"))
)
)Annual Incidence
DT::datatable(
inci_wide,
caption = paste0("Annual incidence per 100 000 — ", prov_name,
" (pop: ", format(prov_pop, big.mark = ","), ")"),
extensions = "Buttons",
filter = "top",
rownames = FALSE,
options = list(
dom = "Bfrtip",
buttons = c("csv", "excel", "pdf"),
pageLength = 25,
scrollX = TRUE
)
)Monthly Detail
DT::datatable(
sd_monthly,
caption = paste0("Monthly data — ", prov_name, " (linked to filter above)"),
extensions = "Buttons",
filter = "top",
rownames = FALSE,
options = list(
dom = "Bfrtip",
buttons = c("csv", "excel"),
pageLength = 20,
scrollX = TRUE
)
)